package com.hexun.dubbo.overview;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.hexun.dubbo.anno.ApiMonitor;
import org.jboss.resteasy.core.ResourceInvoker;
import org.jboss.resteasy.core.ResourceMethodInvoker;

import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;

class ResourceDescription {

    /**
     * base path
     */
    String basePath;

    /**
     * http method calls
     */
    List<MethodDescription> calls;


    /**
     * constructor
     *
     * @param basePath
     */
    private ResourceDescription(String basePath) {
        this.basePath = basePath;
        this.calls = new ArrayList<>();
    }

    /**
     * add method
     *
     * @param path
     */
    private void addMethod(String path, ResourceMethodInvoker resourceInvoker, ApiMonitor monitor) {
        MethodDescription methodDescription = new MethodDescription();
        methodDescription.apiMonitor = monitor;
        methodDescription.resourceInvoker = resourceInvoker;
        methodDescription.method = resourceInvoker.getMethod();
        methodDescription.path = path;
        calls.add(methodDescription);
    }



    /**
     * 根据 basepath 和 subpath 组合成完整 url
     *
     * @param basePath class annotation path
     * @param subPath  method annotation path
     * @return full path
     */
    static String getFullPath(String basePath, String subPath) {
        if (basePath == null) {
            return subPath;
        }
        if (subPath == null) {
            return basePath;
        }
        if (basePath.endsWith("/") || subPath.startsWith("/")) {
            return basePath + subPath;
        }
        return basePath + "/" + subPath;
    }

    /**
     * resolve all bound
     *
     * @param bound
     * @return
     */
    static List<ResourceDescription> fromBoundResourceInvokers(Set<Map.Entry<String, List<ResourceInvoker>>> bound) {
        Map<String, ResourceDescription> descriptions = new HashMap<String, ResourceDescription>();

        for (Map.Entry<String, List<ResourceInvoker>> entry : bound) {
            List<ResourceInvoker> resourceInvokers = entry.getValue();
            Method aMethod = resourceInvokers.get(0).getMethod();
            String basePath = aMethod.getDeclaringClass().getAnnotation(Path.class).value();

            if (!descriptions.containsKey(basePath)) {
                ResourceDescription description = new ResourceDescription(basePath);
                descriptions.put(basePath, description);
            }

            for (ResourceInvoker invoker : resourceInvokers) {
                ResourceDescription description = descriptions.get(basePath);
                ResourceMethodInvoker methodInvoker = (ResourceMethodInvoker) invoker;
                String subPath = null;
                ApiMonitor annoApiMonitor = null;
                for (Annotation annotation : methodInvoker.getMethodAnnotations()) {
                    if (subPath == null) {
                        if (annotation.annotationType().equals(Path.class)) {
                            subPath = ((Path) annotation).value();
                        }
                    }
                    if (annoApiMonitor == null) {
                        if (annotation.annotationType().equals(ApiMonitor.class)) {
                            annoApiMonitor = (ApiMonitor) annotation;
                        }
                    }
                }
                description.addMethod(getFullPath(basePath, subPath), methodInvoker, annoApiMonitor);
            }
        }
        return new ArrayList<>(descriptions.values());
    }
}